package negocio;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;

import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;


import beans.DepositoVO;


@Entity
@Table(name="deposito")
public class Deposito implements Serializable  {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Id @GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name="id_deposito", nullable=false)
	private int id_deposito;
	
	@Column(name="nombre", nullable=true)
	private String nombre;
		
	@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinColumn(name="id_deposito", referencedColumnName="id_deposito")
	private List<Movimiento> movimientos;
	
	@OneToOne(cascade=CascadeType.ALL)
	@JoinColumn(name="id_deposito", referencedColumnName="id_deposito")
	private SolicitudReposicion solicitudReposicion;
	
	@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinColumn(name="id_deposito", referencedColumnName="id_deposito", nullable=false)
	private Set<ProductoEstimado> productosEstimados;
	
	public Deposito()
	{
		movimientos = new ArrayList<Movimiento>();
		solicitudReposicion = new SolicitudReposicion();
		productosEstimados = new HashSet<ProductoEstimado>();
		
	}
	
	public Deposito(String nombre)
	{
		this.nombre = nombre;
		this.movimientos = new ArrayList<Movimiento>();
		this.solicitudReposicion = new SolicitudReposicion();
		solicitudReposicion.setSector(nombre);
		this.productosEstimados = new HashSet<ProductoEstimado>();
	}
	
	public List<Movimiento> getMovimientos() {
		return movimientos;
	}
	public void setMovimientos(List<Movimiento> movimientos) {
		this.movimientos = movimientos;
	}

	public SolicitudReposicion getSolicitudReposicion() {
		return solicitudReposicion;
	}

	public void setSolicitudReposicion(SolicitudReposicion solicitudReposicion) {
		this.solicitudReposicion = solicitudReposicion;
	}

	public int getId_deposito() {
		return id_deposito;
	}
	public void setId_deposito(int id_deposito) {
		this.id_deposito = id_deposito;
	}	
	
	public Set<ProductoEstimado> getProductosEstimados() {
		return productosEstimados;
	}

	public void setProductosEstimados(Set<ProductoEstimado> productosEstimados) {
		this.productosEstimados = productosEstimados;
	}

	public DepositoVO getVO()
	{
		/*TODO: no es realmente necesario
		 * 
		DepositoVO depVO = new DepositoVO();
		ArrayList<MovimientoVO> movimientosVO = new ArrayList<MovimientoVO>();
		for (int i = 0 ; i < getMovimientos().size() ; i++)
		{
			MovimientoVO movVO = new MovimientoVO();
			movVO.setCantidad(getMovimientos().get(i).getCantidad());
			movVO.setFechaCompra(getMovimientos().get(i).getFechaCompra());
			movVO.setFechaVencimiento(getMovimientos().get(i).getFechaVencimiento());
			movVO.setId_movimiento(getMovimientos().get(i).getId_movimiento());
			movVO.setProducto(getMovimientos().get(i).getProducto().getVO());
			movVO.setResponsable(getMovimientos().get(i).getResponsable());
			
			movimientosVO.add(movVO);
		}
		depVO.setMovimientos(movimientosVO);
		ArrayList<ItemSolicitudReposicionVO> itemsVO = new ArrayList<ItemSolicitudReposicionVO>();
		Iterator<ItemSolicitudReposicion> it = getItemsRepocision().iterator();
		while(it.hasNext())
		{
			ItemSolicitudReposicionVO itemVO = new ItemSolicitudReposicionVO();
			itemVO.setCantidad(it.next().getCantidad());
			itemVO.setId_item_solicitud_reposicion(it.next().getId_item_solicitud_reposicion());
			itemVO.setProducto(it.next().getProducto().getVO());
			itemsVO.add(itemVO);
		}
		depVO.setItemsRepocision(itemsVO);
		return depVO;
		*/
		return null;
	}
	
	@Override
	public String toString() {
		return "Deposito [id_deposito=" + id_deposito + ", movimientos="
				+ movimientos + ", solicitudReposicion=" + solicitudReposicion
				+ ", productosEstimados=" + productosEstimados + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id_deposito;
		result = prime * result
				+ ((movimientos == null) ? 0 : movimientos.hashCode());
		result = prime
				* result
				+ ((productosEstimados == null) ? 0 : productosEstimados
						.hashCode());
		result = prime
				* result
				+ ((solicitudReposicion == null) ? 0 : solicitudReposicion
						.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Deposito other = (Deposito) obj;
		if (id_deposito != other.id_deposito)
			return false;
		if (movimientos == null) {
			if (other.movimientos != null)
				return false;
		} else if (!movimientos.equals(other.movimientos))
			return false;
		if (productosEstimados == null) {
			if (other.productosEstimados != null)
				return false;
		} else if (!productosEstimados.equals(other.productosEstimados))
			return false;
		if (solicitudReposicion == null) {
			if (other.solicitudReposicion != null)
				return false;
		} else if (!solicitudReposicion.equals(other.solicitudReposicion))
			return false;
		return true;
	}
	
	public Deposito buildFromVO(DepositoVO depositoVO)
	{
		//TODO
		return null;
	}
	
	public void agregarProductoEstimado(ProductoEstimado productoEstimado)
	{
		if(!existeProducto(productoEstimado.getProducto()))
			productosEstimados.add(productoEstimado);
	}
	
	private boolean existeProducto(Producto producto)
	{
		for(ProductoEstimado p : productosEstimados){
			if(p.getProducto().getNombre().equals
					(producto.getNombre()))
				return true;
		}
		return false;
	}
	
	public float calcularStock(Producto p)
	{
		ArrayList<Movimiento> ms = obtenerMovimientosProducto(p);
		float sumaMovimientos = 0;
		for(Movimiento m : ms){
			sumaMovimientos += m.getCantidad();
		}
		return sumaMovimientos;
	}
	
	private ArrayList<Movimiento> obtenerMovimientosProducto(Producto p)
	{
		ArrayList<Movimiento> resultado = new ArrayList<Movimiento>();
		for(Movimiento m : movimientos){
			if(m.getProducto().equals(p))
				resultado.add(m);
		}
		return resultado;
	}
	
	public Movimiento realizarMovimiento(Producto producto, float cantidad,
			String responsable, Date fechaCompra, Date fechaVencimiento,
			int nroLote)
	{
		Movimiento m = new Movimiento();
		m.setCantidad(cantidad);
		m.setFechaCompra(fechaCompra);
		m.setFechaVencimiento(fechaVencimiento);
		m.setProducto(producto);
		m.setResponsable(responsable);
		m.setNroLote(nroLote);
		movimientos.add(m);
		
		ProductoEstimado p = obtenerProductoEstimado(producto);
		if(alcanzoStockReposicion(p)){
			float stockAReponer = 
					p.getEstimadoDiario() - calcularStock(producto);
			agregarItemSolicitudReposicion(producto, stockAReponer);
		}
		
		return m;
	}
	
	private ProductoEstimado obtenerProductoEstimado(Producto producto)
	{
		for(ProductoEstimado p : productosEstimados){
			if(p.getProducto().equals(producto))
				return p;
		}
		return null;
	}
	
	private boolean alcanzoStockReposicion(ProductoEstimado p)
	{
		return calcularStock(p.getProducto()) <= p.getStockReposicion();
	}
	
	public void agregarItemSolicitudReposicion(Producto producto, float cantidad)
	{
		ItemSolicitudReposicion item = buscarItemProducto(producto);
		if(item == null){
			item = new ItemSolicitudReposicion();
			item.setProducto(producto);
		}
		item.setCantidad(cantidad);
		solicitudReposicion.agregarItem(item);
	}
	
	private ItemSolicitudReposicion buscarItemProducto(Producto producto)
	{
		for(ItemSolicitudReposicion item : solicitudReposicion.getItems())
		{
			if(item.getProducto().equals(producto))
				return item;
		}
		return null;
	}
	
	public void verificarStocksItemsSolicitud()
	{
		List<ItemSolicitudReposicion> items = solicitudReposicion.getItems();
		for(ItemSolicitudReposicion item : items){
			if(item.getCantidad() <= calcularStock(item.getProducto()))
				items.remove(item);
		}
	}
}
